import ddf.minim.*;
import controlP5.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;



ControlP5 controlP5;
Minim minim;
AudioPlayer groove;
AudioMetaData meta;
AudioOutput out;
WaveformRenderer waveform;

ControlWindow openWindow;
Button openButton;
Button playButton;
Button stopButton;
Button loopButton;
Slider positionSlider;
Slider volumeSlider;
Textlabel song;
Textlabel author;
Textlabel album;
Textlabel genre;
Textlabel length;
Textlabel loop;
Textfield currentFolderField;
boolean drag;
boolean lastDrag;
boolean preLastDrag;
float pos;
String currentFolder = "C:\\";
ListBox openFolderList;
ListBox songList;

int numOfSongs;
String[] filenames = new String[100];
String[] songs = new String[100];
File[] files = new File[100];

int waitTillStop;
int waitTillStart;

void setup()
{
  background(0);
  size(768, 200, P2D);
  frameRate(30);
  smooth();

  minim = new Minim(this);
  //groove = minim.loadFile("J:\\Musik\\Coldplay\\Life in technicolor II.mp3", 512);
  //meta = groove.getMetaData();

  //waveform = new WaveformRenderer();
  //groove.addListener(waveform);


  controlP5 = new ControlP5(this);
  openButton = controlP5.addButton("Open",0,2,2,60,19);
  playButton = controlP5.addButton("Play",0,64,2,60,19);
  stopButton = controlP5.addButton("Stop",0,64,2,60,19);
  stopButton.hide();
  loopButton = controlP5.addButton("Loop",0,126,2,60,19);
  positionSlider = controlP5.addSlider("Position",0,0,0,2,190,400,10);

  volumeSlider = controlP5.addSlider("Vol",-80,6,100,400,2,80,19);

  loop = new Textlabel(this,"loop", 460,190, 256, 10);
  loop.setFont(ControlP5.standard56);
  loop.setColorValue(0x00000000);
  song = new Textlabel(this,"SONG: ", 514,2, 256, 10);
  song.setFont(ControlP5.standard56);
  author = new Textlabel(this,"AUTHOR: ", 514,14, 256, 10);
  author.setFont(ControlP5.standard56);
  album = new Textlabel(this,"ALBUM: ", 514,26, 256, 10);
  album.setFont(ControlP5.standard56);
  length = new Textlabel(this, "0.00", 368,192, 256, 10);
  length.setFont(ControlP5.standard56);
  genre = new Textlabel(this,"GENRE: ", 514,38, 256, 10);
  genre.setFont(ControlP5.standard56);
  setupSongList();
}

public void waitProcess()
{
  waitTillStopProcess();
  waitTillStartProcess();
}

void setupSongList()
{
  songList = controlP5.addListBox("songs",512,80,242,120);
  songList.setItemHeight(15);
  songList.setBarHeight(15);
  songList.disableCollapse();

  songList.captionLabel().toUpperCase(true);
  songList.captionLabel().style().marginTop = 3;
  songList.valueLabel().style().marginTop = 3; // the +/- sign
  songList.setBackgroundColor(color(0,0,50));

  for(int i = 0; i < numOfSongs; i++)
  {
    File file = new File(songs[i]);
    songList.addItem(getSongName(file), i);
  }
}

public void changeSong(String Song)
{
  if(groove != null)
  {
    Stop();
    minim.stop();
    positionSlider.setValue(0);
  }
  groove = minim.loadFile(Song, 512);
  meta = groove.getMetaData();
  out = minim.getLineOut();

  System.gc();

  waveform = new WaveformRenderer();
  groove.addListener(waveform);

  positionSlider.setMax(meta.length()/1000);

  song.setValue("SONG: " + meta.title().toUpperCase());
  author.setValue("AUTHOR: " + meta.author().toUpperCase());
  album.setValue("ALBUM: " + meta.album().toUpperCase());
  length.setValue(str(meta.length()/1000) + ".00");
  genre.setValue("GENRE: " + meta.genre().toUpperCase());
}

void draw()
{
  fill(0, 0, 0, 40);
  rect(0, 0, 768, 200);
  if(groove != null)
  {
    waveform.draw();
    positionSlider.setValue(groove.position()/1000);
  }
  controlP5.draw();
  song.draw(this);
  author.draw(this);
  album.draw(this);
  genre.draw(this);
  loop.draw(this);
  length.draw(this);
  waitProcess();
}

void stop()
{
  if(groove != null)
  {
    Stop();
  }
  minim.stop();
  super.stop();
}

public void Play()
{
  if(groove != null)
  {
    groove.shiftGain(groove.getGain(), volumeSlider.value(), 1000);
    waitTillStop(-1);
    waitTillStart(20);
    playButton.hide();
    stopButton.show();
  }
}

public void Stop()
{
  if(groove != null)
  {
    groove.shiftGain(groove.getGain(), -40, 1000);
    waitTillStart(-1);
    waitTillStop(20);
    playButton.show();
    stopButton.hide();
  }
}

public void Position()
{
  if(groove != null)
  {
    if(positionSlider.value() != groove.position()/1000)
    {
      preLastDrag = lastDrag;
      lastDrag = drag;
      drag = true;
      pos = positionSlider.value();
    }
    else
    {
      preLastDrag = lastDrag;
      lastDrag = drag;
      drag = false;
    }

    if(preLastDrag == true && lastDrag == false && drag == false)
    {
      groove.cue(int(pos*1000));
    }
  }
}

public void Vol()
{
  if(groove != null)
  {
    groove.shiftGain(groove.getGain(), volumeSlider.value(), 1000);
  }
}

public void Loop()
{
  if(groove != null)
  {
    if(groove.isPlaying())
    {
      if(groove.isLooping())
      {
        //pos = positionSlider.value();
        groove.play();
        //groove.cue(int(pos*1000));
        loop.setColorValue(0x00000000);
      }
      else
      {
        pos = positionSlider.value();
        groove.loop();
        groove.cue(int(pos*1000));
        loop.setColorValue(0x5c96e5ff);
      }
    }
    else
    {
      if(groove.isLooping())
      {
        groove.play();
        groove.pause();
        loop.setColorValue(0x00000000);
      }
      else
      {
        groove.loop();
        groove.pause();
        loop.setColorValue(0x5c96e5ff);
      }
    }
  }
}

public void Open()
{
  if(openWindow != null)
  {
    openWindow.clear();
  }
  openWindow = controlP5.addControlWindow("openWindow",100,100,400,300);
  openWindow.hideCoordinates();

  openFolderList = controlP5.addListBox("fileList",2,2,385,280);
  openFolderList.setItemHeight(15);
  openFolderList.setBarHeight(15);

  openFolderList.captionLabel().toUpperCase(true);
  openFolderList.captionLabel().set("Files");
  openFolderList.captionLabel().style().marginTop = 3;
  openFolderList.valueLabel().style().marginTop = 3; // the +/- sign
  openFolderList.setBackgroundColor(color(0,0,50));
  openFolderList.moveTo(openWindow);

  currentFolderField = controlP5.addTextfield("Path", 2, 275, 395, 22);
  currentFolderField.setWindow(openWindow);
  currentFolderField.setValue(currentFolder);


  filenames = listFileNames(currentFolder);
  files = listFiles(currentFolder);
  openFolderList.addItem("..", 0);
  for(int i=0; i<filenames.length ; i++)
  {
    openFolderList.addItem(filenames[i], i+1);
  }
}

void controlEvent(ControlEvent theEvent) {

  if (theEvent.isGroup()) {
    // an event from a group e.g. scrollList
    if(theEvent.group().name() == "fileList")
    {
      changeFolderById(theEvent.group().value());

      currentFolderField.setValue(currentFolder);
    }
    if(theEvent.group().name() == "songs")
    {
      changeSong(songs[int(theEvent.group().value())]);
      setupSongList();
    }
  }
}

public void Path(String theText)
{
  if(theText != currentFolder)
  {
    theText = strReplace(theText, "/", "\\");
    changeFolderByPath(theText);
  }
}

public void changeFolderByPath(String dir)
{
  File check = new File(dir);
  if(check.isDirectory())
  {
    currentFolder = dir;
    openFolderList.clear();
    filenames = listFileNames(currentFolder);
    files = listFiles(currentFolder);
    openFolderList.addItem("..", 0);
    for(int i=0; i<filenames.length ; i++)
    {
      openFolderList.addItem(filenames[i], i+1);
    }
  }
}

public void changeFolderById(float id)
{
  if(id == 0)
  {
    String[] folders = split(currentFolder, "\\");
    if(folders.length != 2)
    {
      currentFolder = "";
      for(int i = 0; i < folders.length-2; i++)
      {
        currentFolder = currentFolder + folders[i] + "\\";
      }
    }

    openFolderList.clear();
    filenames = listFileNames(currentFolder);
    files = listFiles(currentFolder);
    openFolderList.addItem("..", 0);
    for(int i=0; i<filenames.length ; i++)
    {
      openFolderList.addItem(filenames[i], i+1);
    }
  }
  else
  {
    File check = files[int(id-1)];
    if(check.isDirectory())
    {
      currentFolder = currentFolder + filenames[int(id-1)] + "\\";
      openFolderList.clear();
      filenames = listFileNames(currentFolder);
      files = listFiles(currentFolder);
      openFolderList.addItem("..", 0);
      for(int i=0; i<filenames.length ; i++)
      {
        openFolderList.addItem(filenames[i], i+1);
      }
    }
    else
    {
      if(getFileExtensionName(check).indexOf("mp3") != -1)
      {
        if(Arrays.asList(songs).contains(check.getAbsolutePath()) == false)
        {
          songList.addItem(getSongName(check), numOfSongs);
          songs[numOfSongs] = check.getAbsolutePath();
          numOfSongs += 1;
        }
      }
    }
  }
}

//Functions

String[] listFileNames(String dir) {
  File file = new File(dir);
  if (file.isDirectory()) {
    String names[] = file.list();
    return names;
  } 
  else {
    // If it's not a directory
    return null;
  }
}

File[] listFiles(String dir) {
  File file = new File(dir);
  if (file.isDirectory()) {
    File[] files = file.listFiles();
    return files;
  } 
  else {
    // If it's not a directory
    return null;
  }
}

public String getFileExtensionName(File f) {
  if (f.getName().indexOf(".") == -1) {
    return "";
  } 
  else {
    return f.getName().substring(f.getName().length() - 3, f.getName().length());
  }
}

public void waitTillStop(int waitTime)
{
  waitTillStop = waitTime;
}

public void waitTillStopProcess()
{
  if(waitTillStop == 0)
  {
    if(groove != null)
    {
      groove.pause();
    }
  }
  if(waitTillStop > -1)
  {
    waitTillStop--;
  }
}

public void waitTillStart(int waitTime)
{
  waitTillStart = waitTime;
}

public void waitTillStartProcess()
{
  if(waitTillStart == 0)
  {
    if(groove != null)
    {
      groove.play();
    }
  }
  if(waitTillStart > -1)
  {
    waitTillStart--;
  }
}


public String getSongName(File f) {
  if (f.getName().indexOf(".") == -1) {
    return "";
  } 
  else {
    return f.getName().substring(0, f.getName().length() - 4);
  }
}

public String strReplace (String subject, String search, String replace)
{
  StringBuffer  result = new StringBuffer (subject);
  int  pos = 0;
  while (true)
  {
    pos = result.indexOf (search, pos);
    if (pos != -1)
      result.replace (pos, pos + search.length (), replace);
    else
      break;
  }
  return result.toString ();
}


//classes

class WaveformRenderer implements AudioListener
{
  private float[] left;
  private float[] right;

  WaveformRenderer()
  {
    left = null; 
    right = null;
  }

  synchronized void samples(float[] samp)
  {
    left = samp;
  }

  synchronized void samples(float[] sampL, float[] sampR)
  {
    left = sampL;
    right = sampR;
  }

  synchronized void draw()
  {
    // we've got a stereo signal if right or left are not null
    if ( left != null && right != null )
    {
      noFill();
      stroke(255);
      beginShape();
      for ( int i = 0; i < left.length; i++ )
      {
        vertex(i, height/4 + left[i]*50);
      }
      endShape();
      beginShape();
      for ( int i = 0; i < right.length; i++ )
      {
        vertex(i, 3*(height/4) + right[i]*50);
      }
      endShape();
    }
    else if ( left != null )
    {
      noFill();
      stroke(255);
      beginShape();
      for ( int i = 0; i < left.length; i++ )
      {
        vertex(i, height/2 + left[i]*50);
      }
      endShape();
    }
  }
}

